const http = require('http');
const { Stream } = require('stream');
const context = require('./context');
const request = require('./request');
const response = require('./response');

class Application {
    constructor() {
        // 保证不同的koa实例都有各自的context response request
        this.context = Object.create(context);
        this.response = Object.create(response);
        this.request = Object.create(request);

        this.callbacks = [];
    }
    use(fn) {
        this.callbacks.push(fn);
    }

    handleRequest(req, res) {
        // 保证每次请求都是全新的
        const context = Object.create(this.context);
        const response = Object.create(this.response);
        const request = Object.create(this.request);
        context.request = request;
        context.response = response;
        context.req = context.request.req = req;
        context.res = context.response.res = res;
        return context;
    }

    compose(context) {
        let overIndex = -1;
        let index = 0;
        const next = (i) => {
            if (overIndex >= i) {
                throw new Error('call next mutiply');
            }
            overIndex = i;
            if (i === this.callbacks.length) {
                return Promise.resolve();
            }
            let fn = this.callbacks[i];
            if (fn) {
                // 如果有use
                return Promise.resolve(fn(context, next.bind(null, i + 1)));
            } else {
                // 如果没use,返回空的
                return Promise.resolve();
            }
        }

        return next(index);
    }

    listen(...args) {
        // 绑定this
        const server = http.createServer((req, res) => {
            const context = this.handleRequest(req, res);
            this.compose(context).then(() => {
                const body = context.body;
                // 如果是字符串或者buffer类型，直接返回
                if (typeof body === 'string' || Buffer.isBuffer(body)) {
                    res.end(body);
                } else if (body instanceof Stream) {
                    // 流  直接发送给res可写流即可
                    body.pipe(res);
                } else if (typeof body === 'object') {
                    // 对象类型
                    res.end(JSON.stringify(body));
                }
            })
        });

        server.listen(...args);
    }

}

module.exports = Application;